package com.zaofan.utils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import org.apache.commons.httpclient.NameValuePair;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.json.JSONException;

import com.zaofan.constant.PayConstant;
import com.zaofan.constant.UrlConstant;
import com.zaofan.utils.pay.MD5;
import com.zaofan.utils.pay.SignUtils;
import com.zaofan.utils.pay.WeiPayResult;

public class PayUtils {

	/**
	 * 获取订单支付 支付宝请求字符串
	 * 
	 * @param orderNo
	 * @param subject
	 * @param body
	 * @param price
	 * @return
	 */
	public static String getAlipayString(String orderNo, String subject, String body, BigDecimal price) {
		String orderInfo = getAlipayOrderInfo(orderNo, subject, body, price, UrlConstant.ALIPAY_PAY_URL);
		String sign = alipaySign(orderInfo);
		try {
			// 仅需对sign 做URL编码
			sign = URLEncoder.encode(sign, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getAlipaySignType();
		return payInfo;
	}

	/**
	 * 获取 支付宝 套餐支付字符串
	 * 
	 * @param orderNo
	 * @param subject
	 * @param body
	 * @param price
	 * @return
	 */
	public static String getAlipayPackageString(String orderNo, String subject, String body, BigDecimal price) {
		String orderInfo = getAlipayOrderInfo(orderNo, subject, body, price, UrlConstant.ALIPAY_PAY_PACKAGE_URL);
		String sign = alipaySign(orderInfo);
		try {
			// 仅需对sign 做URL编码
			sign = URLEncoder.encode(sign, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getAlipaySignType();
		return payInfo;
	}

	public static String getAlipayGoodsString(String orderNo, String subject, String body, BigDecimal price) {
		String orderInfo = getAlipayOrderInfo(orderNo, subject, body, price, UrlConstant.ALIPAY_PAY_GOODS_URL);
		String sign = alipaySign(orderInfo);
		try {
			// 仅需对sign 做URL编码
			sign = URLEncoder.encode(sign, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getAlipaySignType();
		return payInfo;
	}

	/**
	 * 获取 支付宝 充值字符串
	 * 
	 * @param orderNo
	 * @param subject
	 * @param body
	 * @param price
	 * @return
	 */
	public static String getAlipayRechargeString(String orderNo, String subject, String body, BigDecimal price) {
		String orderInfo = getAlipayOrderInfo(orderNo, subject, body, price, UrlConstant.ALIPAY_PAY_RECHARGE_URL);
		String sign = alipaySign(orderInfo);
		try {
			// 仅需对sign 做URL编码
			sign = URLEncoder.encode(sign, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getAlipaySignType();
		return payInfo;
	}

	public static String getAlipayOrderInfo(String orderNo, String subject, String body, BigDecimal price,
			String notify_url) {
		// 签约合作者身份ID
		String orderInfo = "partner=" + "\"" + PayConstant.APLIPAY_PARTNER + "\"";

		// 签约卖家支付宝账号
		orderInfo += "&seller_id=" + "\"" + PayConstant.APLIPAY_SELLER + "\"";

		// 商户网站唯一订单号
		orderInfo += "&out_trade_no=" + "\"" + orderNo + "\"";

		// 商品名称
		orderInfo += "&subject=" + "\"" + subject + "\"";

		// 商品详情
		orderInfo += "&body=" + "\"" + body + "\"";

		// 商品金额
		orderInfo += "&total_fee=" + "\"" + price + "\"";
		// 服务器异步通知页面路径
		orderInfo += "&notify_url=" + "\"" + notify_url + "\"";

		// 服务接口名称， 固定值
		orderInfo += "&service=\"mobile.securitypay.pay\"";

		// 支付类型， 固定值
		orderInfo += "&payment_type=\"1\"";

		// 参数编码， 固定值
		orderInfo += "&_input_charset=\"utf-8\"";

		// 设置未付款交易的超时时间
		// 默认30分钟，一旦超时，该笔交易就会自动被关闭。
		// 取值范围：1m～15d。
		// m-分钟，h-小时，d-天，1c-当天（无论交易何时创建，都在0点关闭）。
		// 该参数数值不接受小数点，如1.5h，可转换为90m。
		orderInfo += "&it_b_pay=\"30m\"";

		// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
		// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";

		// 支付宝处理完请求后，当前页面跳转到商户指定页面的路径，可空
		orderInfo += "&return_url=\"m.alipay.com\"";

		// 调用银行卡支付，需配置此参数，参与签名， 固定值 （需要签约《无线银行卡快捷 支付》才能使用）
		// orderInfo += "&paymethod=\"expressGateway\"";

		return orderInfo;
	}

	/**
	 * sign the order info. 对订单信息进行签名
	 * 
	 * @param content
	 *            待签名订单信息
	 */
	public static String alipaySign(String content) {
		return SignUtils.sign(content, PayConstant.APLIPAY_RSA_PRIVATE);
	}

	/**
	 * get the sign type we use. 获取签名方式
	 * 
	 */
	public static String getAlipaySignType() {
		return "sign_type=\"RSA\"";
	}

	public static WeiPayResult getWeiPayString(String orderNo, String subject, String body, BigDecimal price) {
		String xml;
		try {
			xml = getWeiPayInfo(orderNo, subject, body, price, UrlConstant.WEI_PAY_URL);
			System.err.println(xml);
			return getWeiResult(xml);
		} catch (UnsupportedEncodingException | JSONException e) {
			e.printStackTrace();
		}
		return new WeiPayResult();
	}

	public static WeiPayResult getWeiPayRecharge(String orderNo, String subject, String body, BigDecimal price) {
		String xml;
		try {
			xml = getWeiPayInfo(orderNo, subject, body, price, UrlConstant.WEI_PAY_RECHAGE_URL);
			System.err.println(xml);
			return getWeiResult(xml);
		} catch (UnsupportedEncodingException | JSONException e) {
			e.printStackTrace();
		}
		return new WeiPayResult();

	}

	public static WeiPayResult getWeiPayPackage(String orderNo, String subject, String body, BigDecimal price) {
		String xml;
		try {
			xml = getWeiPayInfo(orderNo, subject, body, price, UrlConstant.WEI_PAY_PACKAGE_URL);
			System.err.println(xml);
			return getWeiResult(xml);
		} catch (UnsupportedEncodingException | JSONException e) {
			e.printStackTrace();
		}
		return new WeiPayResult();

	}

	public static WeiPayResult getWeiPayGoods(String orderNo, String subject, String body, BigDecimal price) {
		String xml;
		try {
			xml = getWeiPayInfo(orderNo, subject, body, price, UrlConstant.WEI_PAY_GOODS_URL);
			System.err.println(xml);
			return getWeiResult(xml);
		} catch (UnsupportedEncodingException | JSONException e) {
			e.printStackTrace();
		}
		return new WeiPayResult();

	}

	public static String getWeiPayInfo(String orderNo, String subject, String body, BigDecimal price, String notify_url)
			throws JSONException, UnsupportedEncodingException {
		// 接收财付通通知的URL
		StringBuffer xml = new StringBuffer();
		try {
			String nonceStr = genNonceStr();

			xml.append("</xml>");
			List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
			packageParams.add(new NameValuePair("appid", Constants.APP_ID));
			packageParams.add(new NameValuePair("body", "ZAOFAN"));
			packageParams.add(new NameValuePair("mch_id", Constants.MCH_ID));
			packageParams.add(new NameValuePair("nonce_str", nonceStr));
			packageParams.add(new NameValuePair("notify_url", notify_url));
			packageParams.add(new NameValuePair("out_trade_no", orderNo));
			// packageParams.add(new BasicNameValuePair("out_trade_no",
			// genOutTradNo()));
			packageParams.add(new NameValuePair("spbill_create_ip", "127.0.0.1"));
			// 商品价格
			DecimalFormat df = new DecimalFormat("#####0");
			packageParams.add(new NameValuePair("total_fee", df.format(price.multiply(new BigDecimal(100)))));
			// packageParams.add(new BasicNameValuePair("total_fee", "1"));
			packageParams.add(new NameValuePair("trade_type", "APP"));

			String sign = genPackageSign(packageParams);
			packageParams.add(new NameValuePair("sign", sign));

			String xmlstring = toXml(packageParams);

			return xmlstring;

		} catch (Exception e) {
			return null;
		}

	}

	private static String genNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

	private static String toXml(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();
		sb.append("<xml version='1.0' encoding='UTF-8' standalone='yes'>");
		for (int i = 0; i < params.size(); i++) {
			sb.append("<" + params.get(i).getName() + ">");

			sb.append(params.get(i).getValue());
			sb.append("</" + params.get(i).getName() + ">");
		}
		sb.append("</xml>");

		try {
			return new String(sb.toString().getBytes(), "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}

	private static String genPackageSign(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		return packageSign;
	}

	public static WeiPayResult getWeiResult(String xml) {

		WeiPayResult result = new WeiPayResult();
		try {
			String url1 = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
			URL url = new URL(url1);
			URLConnection con = url.openConnection();
			con.setDoOutput(true);
			con.setRequestProperty("Cache-Control", "no-cache");
			con.setRequestProperty("Content-Type", "text/xml");

			OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
			out.write(new String(xml.getBytes("UTF-8")));
			out.flush();
			out.close();
			BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
			StringBuffer sb = new StringBuffer();
			String line = "";
			for (line = br.readLine(); line != null; line = br.readLine()) {
				sb.append(line);
			}
			System.out.println(sb.toString());
			Document document = DocumentHelper.parseText(sb.toString());

			result.setAppId(Constants.APP_ID);
			result.setNonceStr(genNonceStr());
			result.setPackages("Sign=WXPay");
			result.setPartnerId(Constants.MCH_ID);
			result.setTimeStamp(String.valueOf(genTimeStamp()));

			Element root = document.getRootElement();
			List childList = root.elements();
			for (int i = 0; i < childList.size(); i++) {
				Element it = (Element) childList.get(i);
				// 对子节点进行其它操作...
				if ("prepay_id".equals(it.getName())) {
					result.setPrepayId(it.getText());
				}
			}
			List<NameValuePair> signParams = new LinkedList<NameValuePair>();
			signParams.add(new NameValuePair("appid", result.getAppId()));
			signParams.add(new NameValuePair("noncestr", result.getNonceStr()));
			signParams.add(new NameValuePair("package", result.getPackages()));
			signParams.add(new NameValuePair("partnerid", result.getPartnerId()));
			signParams.add(new NameValuePair("prepayid", result.getPrepayId()));
			signParams.add(new NameValuePair("timestamp", result.getTimeStamp()));

			result.setSign(genAppSign(signParams));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;

	}

	private static long genTimeStamp() {
		return System.currentTimeMillis() / 1000;
	}

	private static String genAppSign(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);

		String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		return appSign;
	}

}
